package jfxtras.scene.control;


import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;

import com.sun.javafx.scene.control.skin.SkinBase;

/**
 * 
 * @author Tom Eugelink
 * 
 * Possible extension: drop down list or grid for quick selection
 */
public class SpinnerXCaspianSkin<T> extends SkinBase<SpinnerX<T>, SpinnerXBehavior<T>>
{
	// ==================================================================================================================
	// CONSTRUCTOR
	
	/**
	 * 
	 */
	public SpinnerXCaspianSkin(SpinnerX<T> control)
	{
		super(control, new SpinnerXBehavior<T>(control));
		construct();
	}

	/*
	 * 
	 */
	private void construct()
	{
		// setup component
		createNodes();
		
		// react to value changes in the model
		getSkinnable().valueProperty().addListener(new ChangeListener<T>()
		{
			@Override
			public void changed(ObservableValue<? extends T> observableValue, T oldValue, T newValue)
			{
				refreshValue();
			}
		});
		refreshValue();
	}
	
	/*
	 * 
	 */
	private void refreshValue()
	{
		// get node for this value
		Node lNode = getSkinnable().getCellFactory().call( getSkinnable().getValue() );
		
		// if node changed
		if (valueNode != lNode)
		{
			// remove old, add new
			gridPane.getChildren().remove(valueNode);
			valueNode = lNode;
			gridPane.add(valueNode, 1, 0);
		}
	}
	
	// ==================================================================================================================
	// DRAW
	
	/**
	 * construct the nodes
	 */
	private void createNodes()
	{
		// left arrow
		leftArrow = new Region();
		leftArrow.getStyleClass().add("left-arrow");

		// for showing the value
		valueNode = getSkinnable().getCellFactory().call(null);
		valueNode.getStyleClass().add("value");
		
		// right arrow
		rightArrow = new Region();
		rightArrow.getStyleClass().add("right-arrow");

		// construct a gridpane: one row, three columns
		gridPane = new GridPane();
		gridPane.setHgap(3);
		gridPane.add(leftArrow, 0, 0);
		gridPane.add(valueNode, 1, 0);
		gridPane.add(rightArrow, 2, 0);
		ColumnConstraints column1 = new ColumnConstraints(10, 10, Double.MAX_VALUE);
		column1.setHgrow(Priority.ALWAYS);
		ColumnConstraints column2 = new ColumnConstraints(10);
		ColumnConstraints column3 = new ColumnConstraints(10);
		gridPane.getColumnConstraints().addAll(column3, column1, column2); // middle column gets any extra width

		// we're not catching the mouse events on the individual children, but let it bubble up to the parent and handle it there
		// makes our life much more simple
		gridPane.setOnMouseClicked(new EventHandler<MouseEvent>()
		{
			@Override public void handle(MouseEvent evt)
			{
				// was the click on the left side or right side
				if (evt.getX() < gridPane.getWidth() / 2)
				{
					// left
					getBehavior().decrease();
				}
				else
				{
					// right
					getBehavior().increase();
				}
			}
		});
		
		// add to self
		this.getStyleClass().add(this.getClass().getSimpleName()); // always add self as style class, because CSS should relate to the skin not the control
		getChildren().add(gridPane); 
	}
	private Region leftArrow = null;
	private Node valueNode = null;
	private Region rightArrow = null;
	private GridPane gridPane = null;
}
